package com.factory.rental.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.factory.rental.dto.ReportDTO;
import com.factory.rental.dto.ReportStatisticsDTO;
import com.factory.rental.mapper.ReportMapper;
import com.factory.rental.model.*;
import com.factory.rental.service.ContractService;
import com.factory.rental.service.ReportService;
import com.factory.rental.service.RoomService;
import com.factory.rental.service.TenantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * 报表服务实现类
 */
@Service
public class ReportServiceImpl extends ServiceImpl<ReportMapper, Report> implements ReportService {

    private final TenantService tenantService;
    private final RoomService roomService;
    private final ContractService contractService;

    @Autowired
    public ReportServiceImpl(TenantService tenantService, RoomService roomService, ContractService contractService) {
        this.tenantService = tenantService;
        this.roomService = roomService;
        this.contractService = contractService;
    }

    @Override
    @Transactional
    public Report generateReport(ReportDTO reportDTO) {
        Report report = new Report();
        report.setName(reportDTO.getName());
        report.setType(reportDTO.getType());
        report.setDescription(reportDTO.getDescription());
        report.setStartTime(reportDTO.getStartTime());
        report.setEndTime(reportDTO.getEndTime());
        report.setStatus(Report.ReportStatus.GENERATING);
        report.setCreatedBy(reportDTO.getCreatedBy());
        save(report);

        // 异步生成报表
        CompletableFuture.runAsync(() -> {
            try {
                // 模拟报表生成过程
                Thread.sleep(3000);

                // 生成报表文件路径
                String filePath = generateReportFile(report);
                report.setFilePath(filePath);
                report.setGeneratedTime(LocalDateTime.now());
                report.setStatus(Report.ReportStatus.GENERATED);
            } catch (Exception e) {
                report.setStatus(Report.ReportStatus.FAILED);
                log.error("报表生成失败: {}", e.getMessage(), e);
            }
            updateById(report);
        });

        return report;
    }

    @Override
    public Optional<Report> getReportById(Long id) {
        return Optional.ofNullable(getById(id));
    }

    @Override
    public List<Report> getReportsByType(Report.ReportType type) {
        return lambdaQuery()
                .eq(Report::getType, type)
                .list();
    }

    @Override
    public Page<Report> getAllReports(Pageable pageable) {
        return page(pageable);
    }

    @Override
    @Transactional
    public Report updateReport(Long id, ReportDTO reportDTO) {
        Report report = getById(id);
        if (report == null) {
            throw new RuntimeException("未找到指定ID的报表");
        }
        report.setName(reportDTO.getName());
        report.setType(reportDTO.getType());
        report.setDescription(reportDTO.getDescription());
        report.setStartTime(reportDTO.getStartTime());
        report.setEndTime(reportDTO.getEndTime());
        updateById(report);
        return report;
    }

    @Override
    @Transactional
    public void deleteReport(Long id) {
        if (!removeById(id)) {
            throw new RuntimeException("删除报表失败");
        }
    }

    @Override
    public String exportReport(Long id) {
        Report report = getById(id);
        if (report == null) {
            throw new RuntimeException("未找到指定ID的报表");
        }

        if (report.getStatus() != Report.ReportStatus.GENERATED) {
            throw new RuntimeException("报表尚未生成完成");
        }

        return report.getFilePath();
    }

    @Override
    public ReportStatisticsDTO getReportStatistics() {
        ReportStatisticsDTO statistics = new ReportStatisticsDTO();

        // 租户总数
        long tenantCount = tenantService.count();
        statistics.setTenantCount(tenantCount);

        // 房间总数
        long roomCount = roomService.count();
        statistics.setRoomCount(roomCount);

        // 已出租房间数
        long rentedRoomCount = roomService.lambdaQuery()
                .eq(Room::getStatus, Room.RoomStatus.RENTED)
                .count();
        statistics.setRentedRoomCount(rentedRoomCount);

        // 空置房间数
        statistics.setVacantRoomCount(roomCount - rentedRoomCount);

        // 出租率
        BigDecimal occupancyRate = BigDecimal.ZERO;
        if (roomCount > 0) {
            occupancyRate = new BigDecimal(rentedRoomCount)
                    .divide(new BigDecimal(roomCount), 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal(100));
        }
        statistics.setOccupancyRate(occupancyRate);

        // 本月收入和上月收入（模拟数据）
        statistics.setMonthlyIncome(new BigDecimal("125000.00"));
        statistics.setLastMonthIncome(new BigDecimal("110000.00"));

        // 收入增长率
        BigDecimal incomeGrowthRate = BigDecimal.ZERO;
        if (statistics.getLastMonthIncome().compareTo(BigDecimal.ZERO) > 0) {
            incomeGrowthRate = statistics.getMonthlyIncome()
                    .subtract(statistics.getLastMonthIncome())
                    .divide(statistics.getLastMonthIncome(), 4, RoundingMode.HALF_UP)
                    .multiply(new BigDecimal(100));
        }
        statistics.setIncomeGrowthRate(incomeGrowthRate);

        // 问题反馈数量和待处理问题数量（模拟数据）
        statistics.setFeedbackCount(23L);
        statistics.setPendingFeedbackCount(8L);

        // 出租率统计（按月份）
        Map<String, BigDecimal> occupancyRateByMonth = new LinkedHashMap<>();
        occupancyRateByMonth.put("1月", new BigDecimal("85.2"));
        occupancyRateByMonth.put("2月", new BigDecimal("82.7"));
        occupancyRateByMonth.put("3月", new BigDecimal("88.5"));
        occupancyRateByMonth.put("4月", new BigDecimal("90.1"));
        occupancyRateByMonth.put("5月", new BigDecimal("92.3"));
        occupancyRateByMonth.put("6月", new BigDecimal("93.8"));
        statistics.setOccupancyRateByMonth(occupancyRateByMonth);

        // 合同到期预警（按月份）
        Map<String, Long> contractExpiryWarning = new LinkedHashMap<>();
        contractExpiryWarning.put("7月", 5L);
        contractExpiryWarning.put("8月", 8L);
        contractExpiryWarning.put("9月", 3L);
        contractExpiryWarning.put("10月", 6L);
        contractExpiryWarning.put("11月", 2L);
        contractExpiryWarning.put("12月", 4L);
        statistics.setContractExpiryWarning(contractExpiryWarning);

        // 财务汇总（按类别）
        Map<String, BigDecimal> financialSummary = new LinkedHashMap<>();
        financialSummary.put("租金收入", new BigDecimal("105000.00"));
        financialSummary.put("服务费", new BigDecimal("15000.00"));
        financialSummary.put("押金", new BigDecimal("5000.00"));
        financialSummary.put("其他收入", new BigDecimal("0.00"));
        statistics.setFinancialSummary(financialSummary);

        // 租客画像分析（按年龄段）
        Map<String, Long> tenantPortraitByAge = new LinkedHashMap<>();
        tenantPortraitByAge.put("18-25岁", 15L);
        tenantPortraitByAge.put("26-35岁", 42L);
        tenantPortraitByAge.put("36-45岁", 28L);
        tenantPortraitByAge.put("46-55岁", 10L);
        tenantPortraitByAge.put("56岁以上", 5L);
        statistics.setTenantPortraitByAge(tenantPortraitByAge);

        // 租客画像分析（按性别）
        Map<String, Long> tenantPortraitByGender = new LinkedHashMap<>();
        tenantPortraitByGender.put("男", 55L);
        tenantPortraitByGender.put("女", 45L);
        statistics.setTenantPortraitByGender(tenantPortraitByGender);

        return statistics;
    }

    /**
     * 生成报表文件
     * @param report 报表实体
     * @return 报表文件路径
     * @throws IOException IO异常
     */
    private String generateReportFile(Report report) throws IOException {
        // 这里只是模拟生成报表文件的逻辑
        // 实际应用中，可能需要使用报表生成库如JasperReports、Apache POI等

        String reportDir = "reports/" + report.getId();
        File dir = new File(reportDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        String fileName = report.getName() + "_" +
                LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +
                ".pdf";
        String filePath = reportDir + File.separator + fileName;

        // 模拟创建文件
        File reportFile = new File(filePath);
        reportFile.createNewFile();

        return filePath;
    }
}